home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / boxact.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  32.7 KB  |  1,295 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 5
  2. /* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
  3. #pragma load EUDORA_LOAD
  4. #pragma segment Boxes
  5.     void BoxTrack(TOCType **tocH,int anchor,Boolean shift);
  6.     void BoxCenter(MyWindowPtr win, short mNum);
  7.     void DoSaveSelectedAs(TOCHandle tocH);
  8.     void ShowBoxSizes(MyWindowPtr win);
  9.     void BoxSetPriorities(TOCHandle tocH,Byte priority);
  10.     Boolean BoxDragDividers(Point pt, MyWindowPtr win);
  11.     Boolean BoxFindDivider(Point pt,short *which);
  12. #pragma segment Balloon
  13. /************************************************************************
  14.  * BoxHelp - help for mailboxes
  15.  ************************************************************************/
  16. void BoxHelp(MyWindowPtr win, Point mouse)
  17. {
  18.     short mNum;
  19.     TOCHandle tocH = (TOCHandle) win->qWindow.refCon;
  20.     Rect r;
  21.     short hnum=0;
  22.     short column;
  23.  
  24.     mNum = mouse.v/win->vPitch + GetCtlValue(win->vBar);
  25.     r = win->contR;
  26.     if (PtInRect(mouse,&win->contR))
  27.     {
  28.         if (BoxFindDivider(mouse,&column))
  29.         {
  30.             r.left = (*BoxLines)[column]-1; r.right = r.left+3;
  31.             HelpRect(&r,MBOX_HELP_STRN+column+1,90);
  32.         }
  33.         else
  34.         {
  35.             if (column) r.left = (*BoxLines)[column-1]+1;
  36.             if (column<WID_LIMIT) r.right = (*BoxLines)[column]-1;
  37.             if (column)
  38.                 HelpRect(&r,MBOX_HELP_STRN+WID_LIMIT+column,90);
  39.             else
  40.                 HelpPict(&r,STATUS_HELP_PICT,90);
  41.         }
  42.     }
  43.     else if (mouse.v>win->contR.bottom && GetRLong(BOX_SIZE_SIZE)>mouse.h)
  44.     {
  45.         SetRect(&r,win->contR.left,win->contR.bottom,
  46.                              GetRLong(BOX_SIZE_SIZE),win->contR.bottom+GROW_SIZE);
  47.         HelpRect(&r,MBOX_HELP_STRN+2*WID_LIMIT+1,90);
  48.     }
  49.     
  50. }
  51. #pragma segment Boxes
  52.  
  53. /**********************************************************************
  54.  * BoxUpdate - handle an update event for a mailbox window
  55.  **********************************************************************/
  56. void BoxUpdate(MyWindowPtr win)
  57. {
  58.     WindowPeek qw = (WindowPeek) win;
  59.     TOCType **tocH = (TOCType **) qw->refCon;
  60.     MSumType *sum;
  61.     int min, max;
  62.     int line;
  63.     int h,v;
  64.     Str31 states,scratch;
  65.     Rect r,pr,cr;
  66.     short h0;
  67.     short greyMax;
  68.     
  69.     /*
  70.      * redraw it all if we need to calculate the window width
  71.      */
  72.     if (win->hMax < 0)
  73.     {
  74.         (*tocH)->needRedo = 0;
  75.         return;
  76.     }
  77.     
  78.     /*
  79.      * get ready
  80.      */
  81.     ClipRect(&win->contR);
  82.  
  83.     LDRef(tocH);
  84.     min = GetCtlValue(win->vBar);
  85.     max = min+RoundDiv(win->contR.bottom-win->contR.top,win->vPitch)+1;
  86.     max = MIN((*tocH)->count-1,max);
  87.     h = h0 = -GetCtlValue(win->hBar)*win->hPitch;
  88.     
  89.     /*
  90.      * draw the grey lines
  91.      */
  92.     if (!PrefIsSet(PREF_NO_LINES))
  93.     {
  94.         PenPat(&qd.gray);
  95.         greyMax = (max-min+1)*(short)win->vPitch;
  96.         for (v=0;v<=greyMax;v+=win->vPitch)
  97.         {
  98.             MoveTo(0,v);
  99.             LineTo(INFINITY,v);
  100.         }
  101. #ifdef NEVER
  102.         MoveTo(3*FontWidth/2,0);
  103.         Line(0,INFINITY);
  104. #endif
  105.         for (line=0;line<WID_LIMIT;line++)
  106.         {
  107.             h = h0 + (*BoxLines)[line];
  108.             MoveTo(h,0);
  109.             LineTo(h,INFINITY);
  110.         }
  111.     }
  112.         
  113.     /*
  114.      * now, draw the contents
  115.      */
  116.     sum=(*tocH)->sums+min;
  117.     if (max>(*tocH)->count-1) max = (*tocH)->count-1;
  118.     PenPat(&qd.black);
  119.     GetRString(states,STATE_LABELS);
  120.     v = (1-(GetCtlValue(win->vBar)-min))*win->vPitch - FontDescent;
  121.     r.left = 0;
  122.     r.right = INFINITY;
  123.     pr.left = (3*FontWidth)/2;
  124.     pr.top = (win->vPitch-16)/2;
  125.     pr.bottom = pr.top+16;
  126.     pr.right = pr.left+16;
  127.     OffsetRect(&pr,0,(min-GetCtlValue(win->vBar))*win->vPitch);
  128.     for (line=0; line<=(max-min); line++,sum++,v+=win->vPitch,OffsetRect(&pr,0,win->vPitch))
  129.     {
  130.         cr.bottom = MIN(v+FontDescent+1,win->contR.bottom);
  131.         cr.top = MAX(win->contR.top,cr.bottom-win->vPitch);
  132.         h = h0;
  133.         cr.left = h+1; cr.right = h0+(*BoxLines)[WID_STAT]-1;
  134.         ClipRect(&cr);
  135.         MoveTo(h+FontWidth/2,v);
  136.         DrawChar(states[sum->state]);
  137.         DrawPriority(&pr,sum->priority);
  138.         h = h0 + (*BoxLines)[WID_STAT];
  139.                 
  140.         cr.left = h+1; cr.right = h0+(*BoxLines)[WID_FROM]-1;
  141.         cr.right = MIN(cr.right,win->contR.right);
  142.         if (cr.right-cr.left+2>=FontWidth)
  143.         {
  144.             ClipRect(&cr);
  145.             MoveTo(h+FontWidth/2,v);
  146.             DrawTruncString(sum->from,sum->fromTrunc);
  147.         }
  148.         h = h0 + (*BoxLines)[WID_FROM];
  149.                 
  150.         cr.left = h+1; cr.right = h0+(*BoxLines)[WID_DATE]-1;
  151.         cr.right = MIN(cr.right,win->contR.right);
  152.         if (cr.right-cr.left+2>=FontWidth)
  153.         {
  154.             ClipRect(&cr);
  155.             MoveTo(h+FontWidth/2,v);
  156.             DrawTruncString(sum->date,sum->dateTrunc);
  157.         }
  158.         h = h0 + (*BoxLines)[WID_DATE];
  159.         
  160.         cr.left = h+1; cr.right = h0+(*BoxLines)[WID_SIZE]-1;
  161.         cr.right = MIN(cr.right,win->contR.right);
  162.         if (cr.right-cr.left+2>=FontWidth)
  163.         {
  164.              ClipRect(&cr);
  165.             NumToString((sum->length+1023)/1024,scratch);
  166.             MoveTo(cr.right-FontWidth/4-StringWidth(scratch),v);
  167.             DrawString(scratch);
  168.         }
  169.         h = h0 + (*BoxLines)[WID_SIZE];
  170.         
  171.       ClipRect(&win->contR);
  172.         cr.left = h+1; cr.right = win->contR.right-1;
  173.         if (cr.right-cr.left+2>=FontWidth)
  174.         {
  175.             MoveTo(h+FontWidth/2,v);
  176.             DrawString(sum->subj);
  177.         }
  178.         
  179.         if (sum->selected && win->isActive)
  180.         {
  181.             r.left = 0;
  182.             r.right = INFINITY;
  183.             r.bottom = v + FontDescent;
  184.             r.top = r.bottom - win->vPitch;
  185.             BitClr((Ptr)HiliteMode, pHiliteBit);
  186.             InvertRect(&r);
  187.         }
  188.     }
  189.     
  190.     /*
  191.      * cleanup
  192.      */
  193.     UL(tocH);
  194.     InfiniteClip(win);
  195.     ShowBoxSizes(win);
  196. }
  197.  
  198.  
  199. /**********************************************************************
  200.  * BoxClick - handle a click in the content region of a window
  201.  **********************************************************************/
  202. void BoxClick(MyWindowPtr win,EventRecord *event)
  203. {
  204.     Point pt;
  205.     short startNum,endNum,mNum;
  206.     TOCType **tocH;
  207.     Boolean cmd,shift;
  208.     
  209.     pt = event->where;
  210.     GlobalToLocal(&pt);
  211.     if (!PtInRect(pt,&win->contR)) return;
  212.     if (BoxDragDividers(pt,win)) return;
  213.     shift = (event->modifiers & shiftKey) != 0;
  214.     cmd = (event->modifiers & cmdKey) != 0;
  215.     mNum = pt.v/win->vPitch + GetCtlValue(win->vBar);
  216.     tocH = (TOCType **)((WindowPeek)win)->refCon;
  217.     if (shift)
  218.     {
  219.         for (startNum=0;startNum<(*tocH)->count;startNum++)
  220.             if ((*tocH)->sums[startNum].selected) break;
  221.         if (startNum < (*tocH)->count)
  222.         {
  223.           if (startNum < mNum) endNum = mNum;
  224.             else
  225.             {
  226.                 for (endNum=startNum+1;endNum<(*tocH)->count;endNum++)
  227.                     if (!(*tocH)->sums[endNum].selected) break;
  228.                 endNum--;
  229.                 if (!(*tocH)->sums[endNum].selected) endNum = startNum;
  230.                 startNum = mNum;
  231.             }
  232.         }
  233.         else startNum=endNum=mNum;
  234.     }
  235.     else startNum=endNum=mNum;
  236.  
  237.     SelectBoxRange(tocH,startNum,endNum,cmd,-1,-1);
  238.     BoxTrack(tocH,mNum==startNum?endNum:startNum,cmd&&!shift);
  239.     EnableMenus(win);
  240.     if (ClickType==Double)
  241.         DoDependentMenu(win,FILE_MENU,FILE_OPEN_ITEM,event->modifiers);
  242. }
  243.  
  244.  /************************************************************************
  245.  * BoxTrack - track the mouse in a mailbox window
  246.  ************************************************************************/
  247. void BoxTrack(TOCType **tocH,int anchor,Boolean cmd)
  248. {
  249.     MyWindowPtr win = (*tocH)->win;
  250.     Point pt;
  251.     int lastSpot=anchor;
  252.     int spot;
  253.     int vVal,vMin,vMax,topVis,botVis;
  254.     long lastTicks=0;
  255.     
  256.     while (StillDown())
  257.         if (TickCount()-lastTicks>3)
  258.         {
  259.             lastTicks = TickCount();
  260.             vVal = GetCtlValue(win->vBar);
  261.             vMin = GetCtlMin(win->vBar);
  262.             vMax = GetCtlMax(win->vBar);
  263.             topVis = vVal;
  264.             botVis = (*tocH)->count - (vMax-vVal+1);
  265.             GetMouse(&pt);
  266.             spot = vVal + pt.v/(int)win->vPitch;
  267.             if (spot<vMin) spot=vMin;
  268.             else if (spot>=(*tocH)->count) spot=(*tocH)->count-1;
  269.             if (spot<topVis &&    vVal>vMin || spot>botVis && vVal<vMax)
  270.             {
  271.                 if (spot<topVis)
  272.                     ScrollIt(win,0,topVis-spot);
  273.                 else
  274.                     ScrollIt(win,0,botVis-spot);
  275.             }
  276.             if (spot!=lastSpot)
  277.             {
  278.                 if (!cmd)
  279.                     SelectBoxRange(tocH,anchor,spot,cmd,0,0);
  280.                 else
  281.                 {
  282.                     SelectBoxRange(tocH,anchor,spot,cmd,anchor,lastSpot);
  283.                     SelectBoxRange(tocH,anchor,lastSpot,cmd,anchor,spot);
  284.                 }
  285.                 lastSpot = spot;
  286.             }
  287.         }
  288. }
  289.  
  290. /************************************************************************
  291.  * SelectBoxRange - make a particular range in a mailbox the current selection.
  292.  ************************************************************************/
  293. void SelectBoxRange(TOCType **tocH,int start,int end,Boolean cmd,int eStart,int eEnd)
  294. {
  295.     MyWindowPtr win = (*tocH)->win;
  296.     /*
  297.      * topVis and botVis are overly generous, since it won't hurt to be so
  298.      */
  299.     int topVis = GetCtlValue(win->vBar);
  300.     int botVis = (*tocH)->count-(GetCtlMax(win->vBar)-GetCtlValue(win->vBar));
  301.     int sNum;
  302.     int r1, r2;
  303.     GrafPtr oldPort;
  304.     
  305.     if (!(*tocH)->count) return;
  306.     GetPort(&oldPort); SetPort(win);
  307.     if (end<start) {r1=start;start=end;end=r1;}     /* swap */
  308.     if (eEnd<eStart) {r1=eStart;eStart=eEnd;eEnd=r1;}         /* swap */
  309.     
  310.     r1 = start < (*tocH)->count ? start : (*tocH)->count;
  311.     r2 = end < (*tocH)->count ? end : (*tocH)->count-1;
  312.     
  313.     win->hasSelection = False;
  314.     
  315.     /*
  316.      * first range; from the beginning to just before the new selection range
  317.      */
  318.     if (cmd)
  319.     {
  320.         for (sNum=0;sNum<r1;sNum++)
  321.             if ((*tocH)->sums[sNum].selected)
  322.             {
  323.                 win->hasSelection = True;
  324.                 break;
  325.             }
  326.     }
  327.     else
  328.     {
  329.         for (sNum=0;sNum<r1;sNum++)
  330.             if ((*tocH)->sums[sNum].selected)
  331.             {
  332.                 (*tocH)->sums[sNum].selected = False;
  333.                 if (topVis <= sNum && sNum <= botVis && win->isActive)
  334.                     InvertLine(win,sNum);
  335.             }
  336.     }
  337.     
  338.     /*
  339.      * the new selection range
  340.      */
  341.     if (cmd)
  342.     {
  343.         for (sNum=r1;sNum<=r2;sNum++)
  344.             if (sNum<eStart || sNum > eEnd)
  345.             {
  346.                 (*tocH)->sums[sNum].selected = !(*tocH)->sums[sNum].selected;
  347.                 if (topVis <= sNum && sNum <= botVis && win->isActive)
  348.                     InvertLine(win,sNum);
  349.                 win->hasSelection = win->hasSelection || (*tocH)->sums[sNum].selected;
  350.             }
  351.     }
  352.     else
  353.     {
  354.         for (sNum=r1;sNum<=r2;sNum++)
  355.         {
  356.             if (!(*tocH)->sums[sNum].selected)
  357.             {
  358.                 (*tocH)->sums[sNum].selected = True;
  359.                 if (topVis <= sNum && sNum <= botVis && win->isActive)
  360.                     InvertLine(win,sNum);
  361.             }
  362.         }
  363.         win->hasSelection = r1<=r2;
  364.     }
  365.     
  366.     /*
  367.      * above the new selection range
  368.      */
  369.     if (cmd)
  370.     {
  371.         if (!win->hasSelection)
  372.             for (sNum=r2+1;sNum<(*tocH)->count;sNum++)
  373.                 if ((*tocH)->sums[sNum].selected)
  374.                 {
  375.                     win->hasSelection = True;
  376.                     break;
  377.                 }
  378.     }
  379.     else
  380.     {
  381.         for (sNum=r2+1;sNum<(*tocH)->count;sNum++)
  382.             if ((*tocH)->sums[sNum].selected)
  383.             {
  384.                 (*tocH)->sums[sNum].selected = False;
  385.                 if (topVis <= sNum && sNum <= botVis && win->isActive)
  386.                     InvertLine(win,sNum);
  387.             }
  388.     }
  389.     
  390.     SetPort(oldPort);
  391. }
  392.  
  393. /**********************************************************************
  394.  * BoxActivate - perform extra mailbox processing for activate/deactivate
  395.  **********************************************************************/
  396. void BoxActivate(MyWindowPtr win)
  397. {
  398.     TOCType **tocH;
  399.     int topVis;
  400.     int botVis;
  401.     int sNum;
  402.     Rect r;
  403.     MSumType *sum;
  404.     
  405.     SetPort(win);
  406.     if (win->hasSelection)
  407.     {
  408.         ClipRect(&win->contR);
  409.         tocH = (TOCType **)((WindowPeek)win)->refCon;
  410.         topVis = GetCtlValue(win->vBar);
  411.         botVis = (*tocH)->count -
  412.                                     (GetCtlMax(win->vBar)-GetCtlValue(win->vBar));
  413.         if (botVis==(*tocH)->count) botVis--;
  414.         LDRef(tocH);
  415.         sum = (*tocH)->sums+topVis;
  416.         for (sNum=topVis; sNum<=botVis; sNum++,sum++)
  417.             if (sum->selected) InvertLine(win,sNum);
  418.         UL(tocH);
  419.         SetRect(&r,0,0,INFINITY,INFINITY);
  420.         ClipRect(&r);
  421.     }
  422.     if (win->isActive) EnableMenus(win);
  423. }
  424.  
  425. /**********************************************************************
  426.  * BoxMenu - handle a menu choice for a mailbox
  427.  **********************************************************************/
  428. Boolean BoxMenu(MyWindowPtr win,int menu,int item,short modifiers)
  429. {
  430.     Str63 scratch, which;
  431.     TOCType **tocH = (TOCType **)((WindowPeek)win)->refCon;
  432.     long dirId;
  433.     short function;
  434.     short state;
  435.     uLong when;
  436.     MSumPtr sum;
  437.     
  438.     if (menu==MESSAGE_MENU && item==MESSAGE_QUEUE_ITEM && modifiers&optionKey)
  439.       item = MESSAGE_MOD_Q_ITEM;
  440.     switch (menu)
  441.     {
  442.         case FILE_MENU:
  443.             switch(item)
  444.             {
  445.                 case FILE_OPEN_ITEM:
  446.                     if (win->hasSelection)
  447.                         BoxOpen(win);
  448.                     else
  449.                         return(False);
  450.                     break;
  451.                 case FILE_SAVE_AS_ITEM:
  452.                     DoSaveSelectedAs(tocH);
  453.                     return(True);
  454.                     break;
  455.                 case FILE_PRINT_ITEM:
  456.                 case FILE_PRINT_SELECT_ITEM:
  457.                     if (win->hasSelection)
  458.                         (void) PrintSelectedMessages(tocH,item==FILE_PRINT_SELECT_ITEM);
  459.                     else
  460.                         return(False);
  461.                     break;
  462.                 default:
  463.                     return(False);
  464.             }
  465.             break;
  466.         
  467.         case EDIT_MENU:
  468.             switch(item)
  469.             {
  470.                 case EDIT_CLEAR_ITEM:
  471.                     DoIterativeThingy(tocH,MESSAGE_DELETE_ITEM,modifiers,0);
  472.                     break;
  473.                 case EDIT_SELECT_ITEM:
  474.                     SelectBoxRange(tocH,0,(*tocH)->count-1,False,0,0);
  475.                     break;
  476.                 default:
  477.                     return(False);
  478.                     break;
  479.             }
  480.             break;
  481.             
  482.         case SORT_HIER_MENU:
  483.             SetMyCursor(watchCursor);
  484.             switch(item)
  485.             {
  486.                 case SORT_STATUS_ITEM:
  487.                     SortTOC(tocH,(modifiers&optionKey)?RevSumStatCompare:SumStatCompare);
  488.                     break;
  489.                 case SORT_PRIORITY_ITEM:
  490.                     SortTOC(tocH,(modifiers&optionKey)?RevSumPriorCompare:SumPriorCompare);
  491.                     break;
  492.                 case SORT_SUBJECT_ITEM:
  493.                     SortTOC(tocH,(modifiers&optionKey)?RevSumSubjCompare:SumSubjCompare);
  494.                     break;
  495.                 case SORT_SENDER_ITEM:
  496.                     SortTOC(tocH,(modifiers&optionKey)?RevSumFromCompare:SumFromCompare);
  497.                     break;
  498.                 case SORT_TIME_ITEM:
  499.                     SortTOC(tocH,(modifiers&optionKey)?RevSumTimeCompare:SumTimeCompare);
  500.                     break;
  501.             }
  502.             break;
  503.             
  504.         case MESSAGE_MENU:
  505.             switch(item)
  506.             {
  507.                 case MESSAGE_DELETE_ITEM:
  508.                 case MESSAGE_FORWARD_ITEM:
  509.                 case MESSAGE_REPLY_ITEM:
  510.                 case MESSAGE_REDISTRIBUTE_ITEM:
  511.                 case MESSAGE_SALVAGE_ITEM:
  512.                     DoIterativeThingy(tocH,item,modifiers,0);
  513.                     break;
  514.                 case MESSAGE_QUEUE_ITEM:
  515.                     QueueSelectedMessages(tocH,QUEUED,0);
  516.                     if (SendQueue && PrefIsSet(PREF_AUTO_SEND))
  517.                         DoSendQueue();
  518.                     break;
  519.                 case MESSAGE_MOD_Q_ITEM:
  520.                   when = 0;
  521.                     for (sum=(*tocH)->sums;sum<(*tocH)->sums+(*tocH)->count;sum++)
  522.                         if (sum->state==QUEUED) {when = sum->seconds;break;}
  523.                     if (ModifyQueue(&state,&when))
  524.                     {
  525.                       Boolean now = state==SENT;
  526.                         if (now) state = QUEUED;
  527.                       QueueSelectedMessages(tocH,state,when);
  528.                         if (SendQueue && now) DoSendQueue();
  529.                     }
  530.                     break;
  531.                 default:
  532.                     return(False);
  533.             }
  534.             break;
  535.  
  536.         case SPECIAL_MENU:
  537.             switch(item)
  538.             {
  539.                 case SPECIAL_MAKE_NICK_ITEM:
  540.                     if ((*tocH)->which==OUT) MakeCboxNick(win);
  541.                     else MakeMboxNick(win,modifiers);
  542.                     break;
  543.                 default:
  544.                     return(False);
  545.             }
  546.             break;
  547.             
  548.         case REPLY_TO_HIER_MENU:
  549.             DoIterativeThingy(tocH,MESSAGE_REPLY_ITEM,modifiers,item);
  550.             break;
  551.         case FORWARD_TO_HIER_MENU:
  552.             DoIterativeThingy(tocH,MESSAGE_FORWARD_ITEM,modifiers,item);
  553.             break;
  554.         case REDIST_TO_HIER_MENU:
  555.             DoIterativeThingy(tocH,MESSAGE_REDISTRIBUTE_ITEM,modifiers,item);
  556.             break;
  557.         case PRIOR_MENU:
  558.             BoxSetPriorities(tocH,Display2Prior(item));
  559.             break;
  560.         default:
  561.             if (menu==TRANSFER_MENU)
  562.             {
  563.                 dirId = MyDirId;
  564.                 function = TRANSFER;
  565.             }
  566.             else if (menu<1||menu>=FIND_HIER_MENU) return(False);
  567.             else
  568.             {
  569.                 dirId = (*BoxMap)[menu % MAX_BOX_LEVELS];
  570.                 function = (menu-1)/MAX_BOX_LEVELS;
  571.             }
  572.             switch (function)
  573.             {
  574.                 case TRANSFER:
  575.                     PCopy(scratch,(*tocH)->name);
  576.                     if (GetTransferParams(menu,item,&dirId,which) &&
  577.                             (dirId!=(*tocH)->dirId || !EqualString(which,scratch,False,True)))
  578.                         MoveSelectedMessages(tocH,dirId,which,(modifiers&optionKey)!=0);
  579.                     break;
  580.                 default:
  581.                     return(False);
  582.                     break;
  583.             }
  584.             break;
  585.     }
  586.     return(True);
  587. }
  588.  
  589. /**********************************************************************
  590.  * BoxClose - close a mailbox window, saving the toc if it's dirty
  591.  **********************************************************************/
  592. Boolean BoxClose(MyWindowPtr win)
  593. {
  594.     TOCType **tocH = (TOCType **)((WindowPeek)win)->refCon;
  595.     short sumNum;
  596.     Boolean justHide = False;
  597.     Boolean superClose = PrefIsSet(PREF_SUPERCLOSE) && win->qWindow.visible;
  598.     Boolean squish = NeedAutoCompact(tocH);
  599.     long dirId = (*tocH)->dirId;
  600.     Str31 name;
  601.     
  602.     PCopy(name,(*tocH)->name);
  603.     
  604.     /*
  605.      * first, close all associated message windows
  606.      */
  607.     for (sumNum=(*tocH)->count-1;sumNum>=0;sumNum--)
  608.     {
  609.         if ((*tocH)->sums[sumNum].messH)
  610.         {
  611.             if (superClose)
  612.             {
  613.                 if (!CloseMyWindow((*(MessType **)(*tocH)->sums[sumNum].messH)->win))
  614.                     return(False);
  615.             }
  616.             else
  617.                 justHide = True;
  618.         }
  619.     }
  620.     
  621.     /*
  622.      * write if we're dirty
  623.      */
  624.     if ((*tocH)->dirty) WriteTOC(tocH);
  625.     BoxFClose(tocH);
  626.  
  627.     if (justHide)
  628.     {
  629.         HideWindow(win);
  630.         return(False);
  631.     }
  632.  
  633.     /*
  634.      * now, unlink ourselves from the list
  635.      */
  636.     LL_Remove(TOCList,tocH,(TOCType **));
  637.     
  638.     /*
  639.      * bye, bye love
  640.      */
  641.     DisposHandle(tocH);
  642.     
  643.     /*
  644.      * compact?
  645.      */
  646.     if (squish) CompactMailbox(dirId,name);
  647.     
  648.     return(True); 
  649. }
  650.  
  651. /**********************************************************************
  652.  * BoxOpen - open some messages from within a mailbox
  653.  **********************************************************************/
  654. void BoxOpen(MyWindowPtr win)
  655. {
  656.     MyWindowPtr **wps, *wp, lastWin=nil, w;
  657.     int count;
  658.     TOCType **tocH = (TOCType **)((WindowPeek)win)->refCon;
  659.     int sum,limit;
  660.     int opened;
  661.     
  662.     /*
  663.      * count the ones we need to open
  664.      */
  665.     count = 0;
  666.     for (limit=(*tocH)->count,sum=0; sum<limit; sum++)
  667.     {
  668.         if ((*tocH)->sums[sum].selected)
  669.             if ((*tocH)->sums[sum].messH)
  670.             {
  671.                 WindowPeek winPeek = (*(MessType **)(*tocH)->sums[sum].messH)->win;
  672.                 if (!winPeek->visible)
  673.                     ShowMyWindow(winPeek);
  674.                 SelectWindow(winPeek);
  675.             }
  676.             else
  677.                 count++;
  678.     }
  679.     
  680.     /*
  681.      * create window records for them.    Doing them in one block
  682.      * now, in this segment, will avoid heap fragmentation.  We'll
  683.      * dispose of them later
  684.      */
  685.     if (!count) return;
  686.     wps = NuHandle(count*sizeof(MyWindowPtr));
  687.     if (wps==nil)
  688.     {
  689.         WarnUser(COULDNT_WIN,MemError());
  690.         return;
  691.     }
  692.     else
  693.     {
  694.         opened = count;
  695.         while (opened--)
  696.         {
  697.             wp = NuPtr(sizeof(MyWindow));
  698.             (*wps)[opened] = wp;
  699.         }
  700.         
  701.         opened = 0;
  702.         for (sum=limit-1;!EjectBuckaroo && sum>=0; sum--)
  703.         {
  704.             if ((*tocH)->sums[sum].selected && !(*tocH)->sums[sum].messH)
  705.             {
  706.                 if (!(*wps)[opened])
  707.                 {
  708.                     WarnUser(COULDNT_WIN,0);
  709.                     break;
  710.                 }
  711.                 w = (*wps)[opened];
  712.                 (*wps)[opened++]=nil;
  713.                 if (!(w=GetAMessage(tocH,sum,w,True))) break;
  714.                 NotUsingWindow(w);
  715.                 if (lastWin) ActivateMyWindow(lastWin,False);
  716.                 lastWin = w;
  717.             }
  718.             MonitorGrow();
  719.         }
  720.         for (opened=0;opened<count; opened++)
  721.             if ((*wps)[opened]) DisposPtr((*wps)[opened]);
  722.         DisposHandle(wps);
  723.     }
  724. }
  725.  
  726. /************************************************************************
  727.  * BoxKey - handle keystrokes in a mailbox window
  728.  ************************************************************************/
  729. void BoxKey(MyWindowPtr win, EventRecord *event)
  730. {
  731.     TOCType **tocH = (TOCType **)((WindowPeek)win)->refCon;
  732.     short c = event->message & charCodeMask;
  733.     Boolean cmd = (event->modifiers & (cmdKey|shiftKey)) != 0;
  734.     int mNum = -1;
  735.     long uLetter = UnadornMessage(event)&charCodeMask;
  736.     
  737.     if (leftArrowChar <= uLetter && uLetter <= downArrowChar &&
  738.             win->hasSelection &&
  739.             ((event->modifiers&cmdKey)!=0 ?
  740.                 !PrefIsSet(PREF_NO_CMD_ARROW):PrefIsSet(PREF_PLAIN_ARROW)))
  741.         c = enterChar;
  742.         
  743.     switch (c)
  744.     {
  745.         case leftArrowChar:
  746.         case upArrowChar:
  747.             for (mNum=0;mNum<(*tocH)->count;mNum++)
  748.              if ((*tocH)->sums[mNum].selected) break;
  749.             mNum--;
  750.             if (mNum<0) mNum = 0;
  751.             break;
  752.         case rightArrowChar:
  753.         case downArrowChar:
  754.             for (mNum=(*tocH)->count-1;mNum>=0;mNum--)
  755.                 if ((*tocH)->sums[mNum].selected) break;
  756.             mNum++;
  757.             if (mNum==(*tocH)->count) mNum--;
  758.             break;
  759.         case deleteKey:
  760.             BoxMenu(win,EDIT_MENU,EDIT_CLEAR_ITEM,event->modifiers);
  761.             break;
  762.         case returnChar:
  763.         case enterChar:
  764.             if (win->hasSelection)
  765.             {
  766.                 BoxOpen(win);
  767.                 break;
  768.             }
  769.             /* fall through is deliberate for no selection */
  770.         default:
  771.             if (event->modifiers & cmdKey)
  772.             {
  773.                 if ('1'<=c && c<= '5') BoxSetPriorities(tocH,Display2Prior(c-'0'));
  774.                 else SysBeep(20L);
  775.             }
  776.             else
  777.               AlertStr(NOT_HOME_ALRT, Stop, nil);
  778.             break;
  779.     }
  780.     if (mNum > -1)
  781.     {
  782.         SelectBoxRange(tocH,mNum,mNum,cmd,-1,-1);
  783.         BoxCenter(win,mNum);
  784.     }
  785. }
  786.  
  787. /************************************************************************
  788.  * BoxCenter - center a mailbox around a given line
  789.  ************************************************************************/
  790. void BoxCenter(MyWindowPtr win, short mNum)
  791. {
  792.     TOCType **tocH = (TOCType **)((WindowPeek)win)->refCon;
  793.     int topVis = GetCtlValue(win->vBar);
  794.     int botVis = (*tocH)->count-1-(GetCtlMax(win->vBar)-GetCtlValue(win->vBar));
  795.     
  796.     if (mNum<topVis || mNum>botVis)
  797.     {
  798.         UpdateMyWindow(win);    /* this is a hack.  ScrollIt should be smarter */
  799.         ScrollIt(win,0,(topVis+botVis)/2-mNum);
  800.     }
  801. }
  802.  
  803. /************************************************************************
  804.  * BoxSelectAfter - select the message on or after a given message,
  805.  * if no messages are already selected
  806.  ************************************************************************/
  807. void BoxSelectAfter(MyWindowPtr win, short mNum)
  808. {
  809.     TOCType **tocH = (TOCType **)((WindowPeek)win)->refCon;
  810.     
  811.     if (mNum >=0 && BoxNextSelected(tocH,-1)<0)
  812.     if (win->hasSelection = (*tocH)->count)
  813.     {
  814.         mNum = MIN(mNum,(*tocH)->count-1);
  815.         (*tocH)->sums[mNum].selected = True;
  816.         BoxCenter((*tocH)->win,mNum);
  817.     }
  818. }
  819.  
  820. /************************************************************************
  821.  * BoxCenterSelection - center a selection in a mailbox window
  822.  ************************************************************************/
  823. void BoxCenterSelection(MyWindowPtr win)
  824. {
  825.     TOCType **tocH = (TOCType **)((WindowPeek)win)->refCon;
  826.     int top, bottom;
  827.     
  828.     for (top=0;top<(*tocH)->count;top++)
  829.         if ((*tocH)->sums[top].selected) break;
  830.     for (bottom=(*tocH)->count-1;bottom>=0;bottom--)
  831.         if ((*tocH)->sums[bottom].selected) break;
  832.     if (top<=bottom) BoxCenter(win,(top+bottom)/2);
  833. }
  834.  
  835. /************************************************************************
  836.  *
  837.  ************************************************************************/
  838. Boolean BoxPosition(Boolean save,MyWindowPtr win)
  839. {
  840.     Rect r;
  841.     Boolean zoomed;
  842.     TOCHandle tocH = (TOCHandle) win->qWindow.refCon;
  843.     Str31 name;
  844.     PCopy(name,(*tocH)->name);
  845.     
  846.     if (save)
  847.     {
  848.         utl_SaveWindowPos(win,&r,&zoomed);
  849.         SavePosFork((*tocH)->vRef,(*tocH)->dirId,name,&r,zoomed);
  850.     }
  851.     else
  852.     {
  853.         if (!RestorePosFork((*tocH)->vRef,(*tocH)->dirId,name,&r,&zoomed))
  854.             {UL(tocH); return(False);}
  855.         utl_RestoreWindowPos(win,&r,zoomed,1,FigureZoom,DefPosition);
  856.     }
  857.     return(True);
  858. }
  859.  
  860. /************************************************************************
  861.  * SaveMessageAs - save a message in text only form
  862.  ************************************************************************/
  863. void DoSaveSelectedAs(TOCHandle tocH)
  864. {
  865.     long creator;
  866.     short vRefN, refN;
  867.     short err;
  868.     Str31 scratch,name;
  869.     int sumNum;
  870.     MessType **messH;
  871.     short lastSelected = -1;
  872.     Str255 title;
  873.     
  874.     /*
  875.      * tickle stdfile
  876.      */
  877.     GetPref(scratch,PREF_CREATOR);
  878.     if (*scratch!=4) GetRString(scratch,TEXT_CREATOR);
  879.     BlockMove(scratch+1,&creator,4);
  880.     for (sumNum=0;sumNum<(*tocH)->count;sumNum++)
  881.         if ((*tocH)->sums[sumNum].selected) break;
  882.     MakeMessFileName(tocH,sumNum,name);
  883.     ExcludeHeaders = PrefIsSet(PREF_EXCLUDE_HEADERS);
  884.     Paragraphs = PrefIsSet(PREF_PARAGRAPHS);
  885.     if (err=SFPutOpen(name,&vRefN,creator,'TEXT',&refN,SaveAsFilter,SAVEAS_DLOG))
  886.         return;
  887.     
  888.     OpenProgress();
  889.     
  890.     for (;!err && sumNum<(*tocH)->count;sumNum++)
  891.         if ((*tocH)->sums[sumNum].selected)
  892.         {
  893.             MakeMessTitle(title,tocH,sumNum);
  894.             Progress(NoChange,title);
  895.             messH = (*tocH)->sums[sumNum].messH;
  896.             if (messH || GetAMessage(tocH,sumNum,nil,False))
  897.             {
  898.                 err = SaveAsToOpenFile(refN,(*tocH)->sums[sumNum].messH);
  899.                 if (!messH)
  900.                     CloseMyWindow((*(MessHandle)(*tocH)->sums[sumNum].messH)->win);
  901.             }
  902.         }
  903.  
  904.     CloseProgress();
  905.  
  906.     /*
  907.      * close
  908.      */
  909.     (void) FSClose(refN);
  910.     
  911.     /*
  912.      * report error
  913.      */
  914.     if (err)
  915.     {
  916.         FileSystemError(COULDNT_SAVEAS,name,err);
  917.         FSDelete(name,vRefN);
  918.     }
  919. }
  920.  
  921. /************************************************************************
  922.  * MakeMessFileName - make a default name for save as
  923.  ************************************************************************/
  924. void MakeMessFileName(TOCHandle tocH,short sumNum, UPtr name)
  925. {
  926.     UPtr spot;
  927.     short len = MIN(31,*(*tocH)->sums[sumNum].subj);
  928.     
  929.     BlockMove((*tocH)->sums[sumNum].subj,name,len+1);
  930.     *name = len;
  931.     for (spot=name+1;spot<=name+len;spot++)
  932.         if (*spot==':') *spot = '-';
  933. }
  934.  
  935. /************************************************************************
  936.  * ShowBoxSizes - title a mailbox window
  937.  ************************************************************************/
  938. void ShowBoxSizes(MyWindowPtr win)
  939. {
  940.     TOCHandle tocH = (TOCHandle) win->qWindow.refCon;
  941.     Str31 string;
  942.     long usedBytes,totalBytes;
  943.     Str31 name;
  944.     
  945.     usedBytes = (*tocH)->usedK;
  946.     totalBytes = (*tocH)->totalK;
  947.     PCopy(name,(*tocH)->name);
  948.     ComposeRString(string,BOX_SIZE_FMT,(*tocH)->count,usedBytes,
  949.                                  totalBytes-usedBytes);
  950.     MoveTo(win->contR.left+4,win->contR.bottom+GROW_SIZE-2);
  951.     TextSize(GetRLong(BOX_SIZE_FONT_SIZE));
  952.     DrawString(string);
  953.     TextSize(FontSize);
  954.     MoveTo(win->contR.left,win->contR.bottom);
  955.     Line(INFINITY,0);
  956.     MoveTo(win->contR.left+GetRLong(BOX_SIZE_SIZE)-1,win->contR.bottom);
  957.     Line(0,GROW_SIZE+2);
  958. }
  959.  
  960. /************************************************************************
  961.  * BoxDidResize - handle the size display area
  962.  ************************************************************************/
  963. void BoxDidResize(MyWindowPtr win, Rect *oldContR)
  964. {
  965. #pragma unused(oldContR)
  966.     ControlHandle hBar = win->hBar;
  967.     RedoTOC((TOCHandle)win->qWindow.refCon);
  968.     if (hBar)
  969.     {
  970.         ControlHandle hBar = win->hBar;
  971.         Rect r = (*hBar)->contrlRect;
  972.         short delta = GetRLong(BOX_SIZE_SIZE);
  973.         
  974.         r.left += delta;
  975.         MoveMyCntl(win,hBar,r.left,r.top,r.right-r.left,r.bottom-r.top);
  976.         SetRect(&r,win->contR.left,oldContR->bottom,win->contR.left+delta,
  977.                              oldContR->bottom+GROW_SIZE);
  978.         InvalRect(&r);
  979.     }
  980. }
  981.  
  982. /************************************************************************
  983.  * InvalBoxSizeBox - invalidate a window's size display
  984.  ************************************************************************/
  985. void InvalBoxSizeBox(MyWindowPtr win)
  986. {
  987.     Rect r;
  988.     GrafPtr oldPort;
  989.     GetPort(&oldPort);
  990.     SetPort(win);
  991.     r = win->contR;
  992.     r.top = r.bottom;
  993.     r.bottom = r.top+GROW_SIZE;
  994.     r.right = r.left + GetRLong(BOX_SIZE_SIZE);
  995.     InsetRect(&r,1,1);
  996.     InvalRect(&r);
  997.     SetPort(oldPort);
  998. }
  999.  
  1000. /************************************************************************
  1001.  * BoxGonnaShow - get ready to show a mailbox window
  1002.  ************************************************************************/
  1003. void BoxGonnaShow(MyWindowPtr win)
  1004. {
  1005.     TOCHandle tocH = (TOCHandle) win->qWindow.refCon;
  1006.     SAVE_PORT;
  1007.     SetPort(win);
  1008.     
  1009.     CalcAllSumLengths(tocH);
  1010.     (*tocH)->needRedo = 0;
  1011.     win->update = BoxUpdate;
  1012.     MyWindowDidResize(win,nil);
  1013.     ScrollIt(win,0,-INFINITY);
  1014.     REST_PORT;
  1015. }
  1016.  
  1017. /************************************************************************
  1018.  * PriorityString - turn a priority into a string
  1019.  ************************************************************************/
  1020. UPtr PriorityString(UPtr string,Byte priority)
  1021. {
  1022.     /*
  1023.      * normalize
  1024.      */
  1025.     priority=Prior2Display(priority);
  1026.     GetRString(string,PRIOR_STRN+5+priority);
  1027.     return(string);
  1028. }
  1029.  
  1030. /************************************************************************
  1031.  * SetPriority - set a message's priority
  1032.  ************************************************************************/
  1033. void SetPriority(TOCHandle tocH,short sumNum,short priority)
  1034. {
  1035.     MessHandle messH;
  1036.     Rect r;
  1037.     if (Prior2Display(priority)!=Prior2Display((*tocH)->sums[sumNum].priority))
  1038.     {
  1039.         /* invalidate priority box in the toc */
  1040.         InvalTocBox(tocH,sumNum,WID_STAT);
  1041.         
  1042.         /* set the priority display in the message */
  1043.         if ((messH=(*tocH)->sums[sumNum].messH) && (*messH)->win->qWindow.visible)
  1044.         {
  1045.             if (GetPriorityRect((*messH)->win,&r))
  1046.             {
  1047.                 SAVE_PORT;
  1048.                 SetPort((*messH)->win);
  1049.                 InvalRect(&r);
  1050.                 REST_PORT;
  1051.             }
  1052.         }
  1053.     }
  1054.     (*tocH)->sums[sumNum].priority = priority;
  1055.     (*tocH)->dirty = True;
  1056. }
  1057.  
  1058. /************************************************************************
  1059.  * InvalTocBox - invalidate one area of a mailbox window
  1060.  ************************************************************************/
  1061. void InvalTocBox(TOCHandle tocH,short sumNum,short box)
  1062. {
  1063.     Rect r;
  1064.     
  1065.     if ((*tocH)->win)
  1066.     {
  1067.         SAVE_PORT;
  1068.         SetPort((*tocH)->win);
  1069.     
  1070.         r.top = (sumNum-GetCtlValue((*tocH)->win->vBar))*(*tocH)->win->vPitch;
  1071.         r.bottom = r.top + (*tocH)->win->vPitch;
  1072.         r.left = box ? (*BoxLines)[box-1] : 0;
  1073.         r.right = box < WID_LIMIT ? (*BoxLines)[box] : (*tocH)->win->contR.right;
  1074.         InvalRect(&r);
  1075.         REST_PORT;
  1076.     }
  1077. }
  1078.  
  1079.  
  1080. /************************************************************************
  1081.  * BoxSetPriorities - set the priorities of the selected messages
  1082.  ************************************************************************/
  1083. void BoxSetPriorities(TOCHandle tocH,Byte priority)
  1084. {
  1085.     short sumNum;
  1086.     
  1087.     for (sumNum=0;sumNum<(*tocH)->count;sumNum++)
  1088.         if ((*tocH)->sums[sumNum].selected) SetPriority(tocH,sumNum,priority);
  1089. }
  1090.  
  1091. /************************************************************************
  1092.  * BoxDragDividers - see if the user is trying to drag dividers, and help
  1093.  * him if he is.
  1094.  ************************************************************************/
  1095. Boolean BoxDragDividers(Point pt, MyWindowPtr win)
  1096. {
  1097.     short line;
  1098.     long ticks = TickCount()+GetDblTime();
  1099.     Point mouse;
  1100.     short slop = GetRLong(DOUBLE_TOLERANCE);
  1101.     RgnHandle greyRgn;
  1102.     Rect r,bounds;
  1103.     short h0;
  1104.     short dh;
  1105.     short n;
  1106.     long dvdh;
  1107.     TOCHandle tocH = (TOCHandle)win->qWindow.refCon;
  1108.     SAVE_PORT;
  1109.     
  1110.     if (BoxFindDivider(pt,&line))
  1111.     {
  1112.         while (TickCount()<ticks)
  1113.         {
  1114.             if (!StillDown()) return(False);
  1115.             GetMouse(&mouse);
  1116.             if (ABS(mouse.v-pt.v)>slop) return(False);
  1117.             if (ABS(mouse.h-pt.h)>slop) break;
  1118.         }
  1119.         if (greyRgn = NewRgn())
  1120.         {
  1121.             GetMouse(&mouse);
  1122.             r = bounds = win->contR;
  1123.             r.left = pt.h;
  1124.             r.right = pt.h+1;
  1125.             RectRgn(greyRgn,&r);
  1126.             h0 = -win->hPitch*GetCtlValue(win->hBar);
  1127.             bounds.left = line ? (*BoxLines)[line-1] : 0;
  1128.             bounds.left += h0;
  1129.             dvdh = DragGrayRgn(greyRgn,mouse,&bounds,&win->contR,hAxisOnly,nil);
  1130.             dh = dvdh&0xffff;
  1131.             /*
  1132.              * I don't understand why I have to do this; I guess I don't understand
  1133.              * DragGrayRgn.
  1134.              */
  1135.             GetMouse(&mouse);
  1136.             if (mouse.h<=pt.h && dh>0) dh = 0;
  1137.             if (pt.h+dh<bounds.left) dh = 0;
  1138.             
  1139.             if (dh&0x7fff && (dh = RoundDiv(dh,FontWidth)*FontWidth))
  1140.             {
  1141.                 n = WID_LIMIT;
  1142.                 while (n-->line) (*BoxLines)[n] += dh;
  1143.                 (*BoxLines)[line] == MAX((*BoxLines)[line],bounds.left+3);
  1144.  
  1145.                 SaveBoxLines();
  1146.                 for (win=FrontWindow();win;win=win->qWindow.nextWindow)
  1147.                     if (win->qWindow.windowKind==MBOX_WIN||win->qWindow.windowKind==CBOX_WIN)
  1148.                     {
  1149.                         SetPort(win);
  1150.                         CalcAllSumLengths(tocH);
  1151.                         (*tocH)->needRedo = 0;
  1152.                         InvalContent(win);
  1153.                         MyWindowDidResize(win,nil);
  1154.                     }
  1155.                 REST_PORT;
  1156.             }
  1157.         }
  1158.         return(True);
  1159.     }
  1160.     return(False);
  1161. }
  1162.  
  1163. /************************************************************************
  1164.  * BoxFindDivider - is the current point over a dividing line?
  1165.  * Returns true if it is, and puts the line number in which.
  1166.  * puts the line to the right of the mouse in which if it isn't
  1167.  ************************************************************************/
  1168. Boolean BoxFindDivider(Point pt,short *which)
  1169. {
  1170.     short i, h;
  1171.     MyWindowPtr win=FrontWindow();
  1172.     short h0 = -win->hPitch*GetCtlValue(win->hBar);
  1173.     
  1174.     h = 0;
  1175.     for (i=0;i<WID_LIMIT;i++)
  1176.     {
  1177.         h = h0 + (*BoxLines)[i];
  1178.         if (h-1<=pt.h && pt.h<=h+1) {*which=i;return(True);}
  1179.         if (h>pt.h) {*which=i;return(False);}
  1180.     }
  1181.     *which = WID_LIMIT;
  1182.     return(False);
  1183. }
  1184.  
  1185.  
  1186. /************************************************************************
  1187.  * BoxCursor - change the cursor appropriately
  1188.  ************************************************************************/
  1189. void BoxCursor(Point mouse)
  1190. {
  1191.     MyWindowPtr win=FrontWindow();
  1192.     short h0 = -win->hPitch*GetCtlValue(win->hBar);
  1193.     short which;
  1194.     Rect r = win->contR;
  1195.  
  1196.     if (!CursorInRect(mouse,r,MouseRgn))
  1197.         SetMyCursor(arrowCursor);
  1198.     else
  1199.     {
  1200.         if (BoxFindDivider(mouse,&which))
  1201.         {
  1202.             r.left = h0 + (*BoxLines)[which]-1;
  1203.             r.right = r.left+3;
  1204.             SetMyCursor(DIVIDER_CURS);
  1205.         }
  1206.         else
  1207.         {
  1208.             SetMyCursor(plusCursor);
  1209.             if (!which)
  1210.                 r.right = h0 + (*BoxLines)[0]-1;
  1211.             else
  1212.             {
  1213.                 r.left = h0 + (*BoxLines)[which-1]+1;
  1214.                 if (which<WID_LIMIT)
  1215.                     r.right = h0 + (*BoxLines)[which]-1;
  1216.             }
  1217.         }
  1218.         RectRgn(MouseRgn,&r);
  1219.     }
  1220. }
  1221.  
  1222.  
  1223. /************************************************************************
  1224.  * RedoTOC - figure out how wide a toc is
  1225.  ************************************************************************/
  1226. void RedoTOC(TOCHandle tocH)
  1227. {
  1228.     short subMax;
  1229.     short subStart;
  1230.     short subWidth;
  1231.     short sumNum;
  1232.     MyWindowPtr win = (*tocH)->win;
  1233.     short maxValid = MIN((*tocH)->needRedo,(*tocH)->maxValid);
  1234.  
  1235.     if (maxValid < (*tocH)->count)
  1236.     {
  1237.         Rect r;
  1238.         SAVE_PORT;
  1239.         SetPort(win);
  1240.         /*
  1241.          * invalidate all the new ones
  1242.          */
  1243.         SetRect(&r,-INFINITY/2,-INFINITY/2,INFINITY/2,INFINITY/2);
  1244.         r.top = win->vPitch * (maxValid-GetCtlValue(win->vBar));
  1245.         InvalRect(&r);
  1246.         REST_PORT;
  1247.         (*tocH)->maxValid = (*tocH)->count;
  1248.         UpdateMyWindow(win);
  1249.         MyWindowMaxes(win,win->hMax,(*tocH)->count);
  1250.     }
  1251.  
  1252.     if ((*tocH)->needRedo < (*tocH)->count)
  1253.     {
  1254.         /*
  1255.          * measure all the subject lines
  1256.          */
  1257.         subStart = (*BoxLines)[WID_LIMIT-1];
  1258.         subMax = 0;
  1259.         if (FontIsFixed)
  1260.         {
  1261.             for (sumNum=(*tocH)->needRedo;sumNum<(*tocH)->count;sumNum++)
  1262.                 subMax = MAX(subMax,*(*tocH)->sums[sumNum].subj);
  1263.             subMax *= win->hPitch;
  1264.         }
  1265.         else
  1266.         {
  1267.             SAVE_PORT;
  1268.             SetPort(win);
  1269.             LDRef(tocH);
  1270.             for (sumNum=(*tocH)->needRedo;sumNum<(*tocH)->count;sumNum++)
  1271.             {
  1272.                 subWidth = StringWidth((*tocH)->sums[sumNum].subj);
  1273.                 subMax = MAX(subMax,subWidth);
  1274.             }
  1275.             UL(tocH);
  1276.             REST_PORT;
  1277.         }
  1278.         
  1279.         /*
  1280.          * add in widths of other fields, and convert from chars to pixels
  1281.          */
  1282.         subMax += (*BoxLines)[WID_LIMIT-1];
  1283.         subMax = RoundDiv(subMax,win->hPitch);
  1284.         subMax += 1; /* fudge */
  1285.         
  1286.         /*
  1287.          * install new maximums; take the old max into account only if we're
  1288.          * doing a partial
  1289.          */
  1290.         if ((*tocH)->needRedo) subMax = MAX(subMax,win->hMax);
  1291.         (*tocH)->needRedo = (*tocH)->count;            /* don't need to do this again */
  1292.         MyWindowMaxes(win,subMax,(*tocH)->count);
  1293.     }
  1294. }
  1295.